package com.googlecode.cswish.struts.spring;

import java.util.Collection;
import java.util.List;

import net.sf.ehcache.CacheManager;

import org.hibernate.jdbc.ReturningWork;

import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.model.Reference;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.util.bean.ScannerContext;

/**
 * It provides the generic business operations
 * 
 * @author Jerry.feng
 */
public interface GenericService {
	public final static String OPERATION_MERGE = "merge";
	public final static String OPERATION_DELETE = "delete";
	
	public CacheManager getCacheManager();
	
	/**
	 * Search pagination data
	 * 
	 * @param model any kinds of model or ParameterMap
	 * @param start the start index of record
	 * @param limit the max length of the record
	 * @param sort use "ActionContext.getContext().getValueStack().setValue('sort', sort)" to change the input parameter
	 * @param dir
	 * @param newSearch new search flag
	 * @param qlInfoRef the cache of last search condition
	 * @return
	 */
	public <T> PageInfo<T> search(T model, int start, int limit, String sort, String dir, boolean newSearch, Reference<QLInfo> qlInfoRef);
	
	public <T> PageInfo<T> search(T model, int start, int limit, String sort, String dir, boolean calculateCount);
	
	public <T> PageInfo<T> search(T model, int start, int limit, String sort, String dir, boolean newSearch, Reference<QLInfo> qlInfoRef,
			SearchCallback callback, boolean calculateCount,  boolean disablePermission);
        
    /**
     * Convert model to QL expression and return the table result
     * 
     * @param model
     * @param condition
     * @return
     */
    public <T> PageInfo<T> searchByModel(T model, Condition condition, boolean calculateTotalCount, boolean checkPermission);
    
    public <T> PageInfo<T> searchByModel(T model, Condition condition);
    
    /**
     * search all the data result
     * 
     * @param model
     * @return
     */
    public <T> PageInfo<T> searchAll(T model);
    
    /**
     * calculate the record count
     * 
     * @param qlInfo
     * @return
     */
    public int getCount(QLInfo qlInfo, boolean cacheable);
    
    /**
     * Add user permission filter to the QLInfo
     * 
     * @param qlInfo
     * @param userId
     */
    public void activePermissionFilter(QLInfo qlInfo, String userId);
    
    public PageInfo searchByQl(QLInfo qlInfo);
    
    public PageInfo searchByQl(QLInfo qlInfo, boolean cacheable);
    
    public <T> T add(T model);
    
    public <T> List<T> addList(List<T> model);
    
    public <T> T update(T model);
    
    /**
     * Update model, only the enabled fields can be updated
     * 
     * @param model
     * @param disablePermissionCheck don't check the user permission
     * @param enableFields null means all the fields
     * @param entityInterceptor trigger only when the property is entity
     * @return
     */
    public <T> T update(T model, boolean disablePermissionCheck, Collection<String> enableFields, Executor<ScannerContext, ScannerContext> entityInterceptor);
    
    public <T> T merge(T model);
    
    public void updateList(List<Object> model);

    public boolean delete(Object model);
    
    public boolean delete(Object model, boolean disablePermissionCheck);
    
    public boolean deleteList(List<Object> model);
    
    public <T> T view(T model);

    public <T> T load(T model);
    
    public <T> T load(T model, boolean disablePermissionCheck);
    
    public <T> T load(Class<T> clazz, Object id);
    
    public <T> List<T> load(Class<T> clazz, final List<Object> ids, boolean disablePermissionCheck);
    
    /**
     * Register callback event for the entity operation
     * 
     * @param clazz
     * @param operation see GenericService.OPERATION_xxx, multiple operation split by the ','
     * @param execute, the Object[] parameter is: new model, old model, operation
     */
    public void on(Class<?> clazz, String operations, Executor<?, Object[]> execute, boolean sync);
    
    /**
     * Execute hibernate returning work
     *  
     * @param work
     * @return
     */
    public <T> T doReturningWork(ReturningWork<T> work);
    
    /**
     * Execute the callback in the async model
     * 
     * @param executor
     * @param parameters
     */
    public <T, P> T executeAsync(Executor<T, P> executor, P parameters);
    
    /**
     * Execute the method in the new transaction
     * 
     * @param executor
     * @param parameters
     * @return
     */
    public <T, P> T executeInNewTx(Executor<T, P> executor, P parameters);
    
    /**
     * Execute the callback on the specified site
     * 
     * @param site
     * @param executor
     * @param parameters
     */
    public <T, P> T executeInSite(String site, Executor<T, P> executor, P parameters);
    
    /**
     * Change the entity type
     * 
     * @param model
     * @param discriminatorValue
     * @return
     */
    public <T> T changeModelType(Object model, Class<T> targetType);
}